{-----------------------------------------------------------------

  (c) 2008-2009 Markus Dittrich 
 
  This program is free software; you can redistribute it 
  and/or modify it under the terms of the GNU General Public 
  License Version 3 as published by the Free Software Foundation. 
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License Version 3 for more details.
 
  You should have received a copy of the GNU General Public 
  License along with this program; if not, write to the Free 
  Software Foundation, Inc., 59 Temple Place - Suite 330, 
  Boston, MA 02111-1307, USA.

--------------------------------------------------------------------}

-- | this module parses the contents of a package and
-- puts everything into a list of PackageContent data 
-- structures
module Parsers.Content ( defaultContent
                       , get_content
                       , FileType(..)
                       , PackageContentItem(..) 
                       , retrieve_package_content
                       ) where 


-- basic imports
import qualified Data.ByteString as B(ByteString, null, split, concat)
import Prelude
import System.FilePath.Posix((</>))
import Text.Regex.PCRE((=~))


-- local imports
import Helpers.ByteString(newlineW, remove_last_newline, spaceChar, 
  spaceCharW)
import Helpers.FileIO(read_file)



-- | data type for describing the type of "file"
-- in the PackageContent
data FileType = None | Dir | Sym | Obj 
                deriving(Eq,Show)



-- | data structure for holding a single entry in the 
-- CONTENTS file of a package
data PackageContentItem = PackageContentItem {
  fileType  :: FileType,
  fileName  :: B.ByteString,
  md5       :: B.ByteString,
  modTime   :: B.ByteString
} deriving(Eq,Show)



-- | default Dependency data structure
defaultContent :: PackageContentItem
defaultContent = PackageContentItem {
  fileType  = None, 
  fileName  = spaceChar,
  md5       = spaceChar,
  modTime   = spaceChar 
}



-- | read the CONTENT of a file and return it as a raw 
-- ByteString
get_content :: FilePath -> IO B.ByteString
get_content path = read_file (path </> "CONTENTS")



-- | retrieve content of package located at location path
retrieve_package_content :: FilePath -> IO [PackageContentItem]
retrieve_package_content path = get_content path
                                >>= return . content_parser



-- | split the content into list of lines and then hands them
-- over for parsing of each line
-- NOTE: the passed string may be empty so we need to check
content_parser :: B.ByteString -> [PackageContentItem]
content_parser content 
  | B.null content  = []
  | otherwise       = map (parse_line) splitLines

    where
      lineList = B.split newlineW $ remove_last_newline content
      splitLines = map (B.split spaceCharW) lineList



-- | parse each line and create a corresponding
-- PackageContentItem entry
parse_line :: [B.ByteString] -> PackageContentItem
parse_line []          = defaultContent
parse_line (x:xs) 
  | x =~ "dir"         = defaultContent { 
                            fileType = Dir,
                            fileName = head xs 
                          }
  | x =~ "sym"         = defaultContent {
                            fileType = Sym,
                            fileName = assemble_link xs,
                            modTime  = (!!) xs 3 
                          }
  | x =~ "obj"         = defaultContent {
                            fileType = Obj,
                            fileName = (!!) xs 0,
                            md5      = (!!) xs 1,
                            modTime  = (!!) xs 2
                         }
  | otherwise          = defaultContent

  where
    assemble_link :: [B.ByteString] -> B.ByteString
    assemble_link (a:b:c:_) = 
      B.concat [a, spaceChar, b, spaceChar, c]
    assemble_link _       = spaceChar
